package com.witmore.skyline.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jk.aliyun.oss.JkOssClient;
import com.witmore.skyline.db.entity.*;
import com.witmore.skyline.db.mapper.*;
import com.witmore.skyline.db.mapper.dto.CameraListQuery;
import com.witmore.skyline.web.constants.TableSortConstant;
import com.witmore.skyline.web.constants.TableSortCustomConstant;
import com.witmore.skyline.web.controller.enums.CameraPicSourceTypeEnum;
import com.witmore.skyline.web.controller.enums.WitmoreErrorCode;
import com.witmore.skyline.web.controller.vo.param.CameraBindDeviceParamVO;
import com.witmore.skyline.web.controller.vo.param.CameraListParamVO;
import com.witmore.skyline.web.controller.vo.param.CameraParamVO;
import com.witmore.skyline.web.controller.vo.param.CameraUpdateNameParamVO;
import com.witmore.skyline.web.controller.vo.param.CameraUpdateDeviceSnParamVO;
import com.witmore.skyline.web.controller.vo.result.CameraResultVO;
import com.witmore.skyline.web.controller.vo.result.PageInfo;
import com.witmore.skyline.web.controller.vo.result.ResponsePageResult;
import com.witmore.skyline.web.controller.vo.result.ResponseResult;
import com.witmore.skyline.web.exception.WitmoreException;
import com.witmore.skyline.web.service.CameraService;
import com.witmore.skyline.web.service.MessageService;
import com.witmore.skyline.web.service.PictureAnalysisService;
import com.witmore.skyline.web.service.ProjectService;
import com.witmore.skyline.web.service.third.tplink.ApiCaptureUrlClient;
import com.witmore.skyline.web.service.third.tplink.ApiVmsStreamClient;
import com.witmore.skyline.web.service.third.tplink.dto.*;
import com.witmore.skyline.web.service.third.yjx.client.CameraUrlCache;
import com.witmore.skyline.web.service.third.yjx.dto.CameraDTO;
import com.witmore.skyline.web.service.third.yjx.dto.CameraLiveDTO;
import com.witmore.skyline.web.utils.LocalDateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Description: CameraServiceImpl
 * Author: 豆子高
 * Date: 2025/2/26 15:39
 */
@Slf4j
@Service
public class CameraServiceImpl implements CameraService {

    @Autowired
    private CameraMapper cameraMapper;

    @Autowired
    private DeviceMapper deviceMapper;


    @Lazy
    @Autowired
    private ProjectService projectService;
    @Autowired
    private JkOssClient ossClient;

    @Autowired
    private CameraPicMapper cameraPicMapper;
    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private OrgMapper orgMapper;

    @Autowired
    private MessageService messageService;

    @Autowired
    private PictureAnalysisService pictureAnalysisService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void getAndSaveCameraList(DeviceDO deviceDO, List<CameraDTO> cameraDTOS) {
        if (CollectionUtils.isEmpty(cameraDTOS)) {
            return;
        }
        // 保存或更新摄像头信息 以及 保存或更新设备与摄像头的关系
        cameraDTOS.forEach(cameraDTO -> {
            // TODO TPLink摄像头 不从云机械拉取 因为平台加了绑摄像头的功能
            if (cameraDTO.getType() == 2) {
                return;
            }
            List<CameraDO> cameraDOS = cameraMapper.selectList(new LambdaQueryWrapper<CameraDO>()
                    .eq(CameraDO::getCameraSn, cameraDTO.getSerialNo())
            );

            if (CollectionUtils.isEmpty(cameraDOS)) {
                // 保存摄像头信息，直接设置项目部ID
                CameraDO cameraDO = new CameraDO();
                cameraDO.setCameraName(cameraDTO.getName());
                cameraDO.setCameraSn(cameraDTO.getSerialNo());
                cameraDO.setOrgId(deviceDO.getOrgId());
                cameraDO.setProjectId(9999); // 默认挂在 projectId = 9999 表示默认项目
                cameraDO.setType(cameraDTO.getType());
                cameraDO.setCameraStatus(cameraDTO.getStatus());
                cameraDO.setCreateTime(LocalDateTime.now());
                cameraDO.setUpdateTime(LocalDateTime.now());
                cameraDO.setSkylineDeviceId(deviceDO.getId());
                cameraDO.setDeviceSn(deviceDO.getDeviceSn());
                cameraMapper.insert(cameraDO);
            } else {
                // 查询cameraDOS中有没有is_deleted = 0 的数据 只更新 这个数据
                CameraDO cameraDb = cameraDOS.stream().filter(cameraDO -> cameraDO.getIsDeleted() == 0).findFirst().orElse(null);
                if (null == cameraDb) {
                    return;
                }
                // 更新摄像头信息
                CameraDO cameraUpdate = new CameraDO();
                cameraUpdate.setId(cameraDb.getId());
                cameraUpdate.setCameraName(cameraDTO.getName());
                cameraUpdate.setCameraSn(cameraDTO.getSerialNo());
                cameraUpdate.setOrgId(deviceDO.getOrgId());
                cameraUpdate.setType(cameraDTO.getType());
                cameraUpdate.setCameraStatus(cameraDTO.getStatus());
                cameraUpdate.setIsDeleted(0);
                cameraUpdate.setUpdateTime(LocalDateTime.now());
                cameraMapper.updateById(cameraUpdate);
            }
        });
    }

    @Override
    public ResponseResult<CameraLiveDTO> getCameraLiveUrl(CameraParamVO cameraParamVO) {
        if (null == cameraParamVO || StringUtils.isEmpty(cameraParamVO.getCameraSn())) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR);
        }
        // 摄像头在线状态参数
        this.cameraStatusCheck(cameraParamVO.getCameraSn());
        return ResponseResult.success(CameraUrlCache.getCameraUrl(cameraParamVO));

    }

    @Override
    public ResponsePageResult<CameraResultVO> getCameraList(CameraListParamVO paramVO) {
        List<Integer> cameraIdListParam = new ArrayList<>();
        // 项目管理员 角色进入
        if (null != paramVO.getProjectId()) {
            if (null != paramVO.getProjectIdQuery()) {
                //  校验 projectIdQuery是否属于 当前项目管理员所管辖范围
                List<Integer> projectIdsWithChildren = projectService.getProjectIdsWithChildren(paramVO.getProjectId());
                if (!projectIdsWithChildren.contains(paramVO.getProjectIdQuery())) {
                    return ResponsePageResult.fail(WitmoreErrorCode.ADMIN_TYPE_ERROR);
                }
            } else {
                // 根据当前传入的 项目id 查询项目下的所有业务id包含子项目
                cameraIdListParam = projectService.getBusinessIdListByProjectId(paramVO.getOrgId(), paramVO.getProjectId(), 2);
                if (cameraIdListParam.isEmpty()) {
                    // 当选择了 项目部 却没查到项目下的业务信息 则说明没有 直接返回 空集合
                    return ResponsePageResult.success(new ArrayList<>(),
                            new PageInfo(paramVO.getPage(), paramVO.getSize(), 0, 0));
                }
            }
        }
        // 根据用户主动传入的项目id 查询当前项目下直属的视频id
        if (null != paramVO.getProjectIdQuery()) {
            cameraIdListParam = projectService.getBusinessIdList(paramVO.getOrgId(), Collections.singletonList(paramVO.getProjectIdQuery()), 2);
            if (cameraIdListParam.isEmpty()) {
                // 当选择了 项目部 却没查到项目下的业务信息 则说明没有 直接返回 空集合
                return ResponsePageResult.success(new ArrayList<>(),
                        new PageInfo(paramVO.getPage(), paramVO.getSize(), 0, 0));
            }
        }
        Page<CameraDO> cameraDOPage;
        // 当需要查询设备相关信息（设备名称、省份、城市）时，使用自定义查询
        if (StringUtils.isNotEmpty(paramVO.getDeviceName()) ||
            StringUtils.isNotEmpty(paramVO.getProvince()) ||
            StringUtils.isNotEmpty(paramVO.getCity())) {
            CameraListQuery cameraListQuery = new CameraListQuery();
            cameraListQuery.setCameraSn(paramVO.getCameraSn());
            cameraListQuery.setCameraName(paramVO.getCameraName());
            cameraListQuery.setDeviceSn(paramVO.getDeviceSn());
            cameraListQuery.setDeviceName(paramVO.getDeviceName());
            cameraListQuery.setProvince(paramVO.getProvince());
            cameraListQuery.setCity(paramVO.getCity());
            cameraListQuery.setOrgId(paramVO.getOrgId());
            cameraListQuery.setCameraIds(cameraIdListParam);
            // 排序字段
            Map<String, String> stringStringMap = TableSortCustomConstant.convertToDbFieldCamera(paramVO.getSortField(), paramVO.getSortOrder());
            cameraListQuery.setSortField(stringStringMap.get("dbSortField"));
            cameraListQuery.setSortOrder(stringStringMap.get("dbSortOrder"));
            // 分页
            int count = cameraMapper.selectCountCustom(cameraListQuery);
            if (count == 0) {
                return ResponsePageResult.success(new ArrayList<>(),
                        new PageInfo(paramVO.getPage(), paramVO.getSize(), 0, 0));
            }
            // 总页数
            int totalPage = count % paramVO.getSize() == 0 ? count / paramVO.getSize() : count / paramVO.getSize() + 1;
            if (paramVO.getPage() > totalPage) {
                return ResponsePageResult.fail(4002, "当前页数超出总页数");
            }
            cameraDOPage = cameraMapper.selectPageCustom(new Page<>(paramVO.getPage(), paramVO.getSize()), cameraListQuery);
        } else {
            // 封装查询参数
            LambdaQueryWrapper<CameraDO> queryWrapper = new LambdaQueryWrapper<CameraDO>()
                    .eq(CameraDO::getIsDeleted, 0)
                    .in(!ObjectUtils.isEmpty(cameraIdListParam), CameraDO::getId, cameraIdListParam)
                    .eq(CameraDO::getOrgId, paramVO.getOrgId())
                    .eq(!ObjectUtils.isEmpty(paramVO.getCameraSn()), CameraDO::getCameraSn, paramVO.getCameraSn())
                    .like(!ObjectUtils.isEmpty(paramVO.getCameraName()), CameraDO::getCameraName, paramVO.getCameraName())
                    .eq(!ObjectUtils.isEmpty(paramVO.getDeviceSn()), CameraDO::getDeviceSn, paramVO.getDeviceSn());
            // 使用条件排序处理
            TableSortConstant.convertToDbFieldCamera(queryWrapper, paramVO.getSortField(), paramVO.getSortOrder());
            // 总数量
            cameraDOPage = cameraMapper.selectPage(new Page<>(paramVO.getPage(), paramVO.getSize()), queryWrapper);
        }
        if (cameraDOPage == null || ObjectUtils.isEmpty(cameraDOPage.getRecords())) {
            return ResponsePageResult.fail(WitmoreErrorCode.CAMERA_GET_FAIL);
        }
        List<CameraDO> records = cameraDOPage.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return ResponsePageResult.success(new ArrayList<>(),
                    new PageInfo(cameraDOPage.getCurrent(), cameraDOPage.getSize(), cameraDOPage.getTotal(), cameraDOPage.getPages()));
        }
        // 封装 设备信息 & 图片信息
        List<CameraResultVO> cameraResultVOS = new ArrayList<>();
        records.forEach(cameraDO -> {
            CameraResultVO build = CameraResultVO.builder()
                    .id(cameraDO.getId())
                    .cameraName(cameraDO.getCameraName())
                    .cameraSn(cameraDO.getCameraSn())
                    .orgId(cameraDO.getOrgId())
                    .type(cameraDO.getType())
                    .modelId(cameraDO.getModelId())
                    .modelName(cameraDO.getModelName())
                    .cameraStatus(cameraDO.getCameraStatus())
                    .build();
            if (null == paramVO.getNeedCameraPic() || paramVO.getNeedCameraPic()) {
                // 图片信息
                Page<CameraPicDO> cameraPicDOPage = cameraPicMapper.selectPage(new Page<>(1, paramVO.getCameraPicCount()), new LambdaQueryWrapper<CameraPicDO>()
                        .eq(CameraPicDO::getCameraSn, cameraDO.getCameraSn())
                        .eq(CameraPicDO::getOrgId, cameraDO.getOrgId())
                        .orderByDesc(CameraPicDO::getId)
                );
                if (cameraPicDOPage != null && !CollectionUtils.isEmpty(cameraPicDOPage.getRecords())) {
                    build.setCameraPicList(cameraPicDOPage.getRecords());
                }
            }
            build.setProjectName(projectService.getProjectNameByBusinessId(build.getId(), 2));
            DeviceDO deviceDO = deviceMapper.selectById(cameraDO.getSkylineDeviceId());
            if (deviceDO == null) {
                return;
            }
            build.setDeviceSn(deviceDO.getDeviceSn());
            build.setDeviceName(deviceDO.getDeviceName());
            build.setCurrentAddr(deviceDO.getCurrentAddr());
            build.setLng(deviceDO.getLng());
            build.setLat(deviceDO.getLat());
            build.setWorkStatus(deviceDO.getWorkStatus());
            build.setWorkTime(deviceDO.getWorkTime());
            build.setTodayWorkTime(deviceDO.getTodayWorkTime());
            build.setOilLevel(deviceDO.getOilLevel());
            cameraResultVOS.add(build);
        });
        return ResponsePageResult.success(cameraResultVOS,
                new PageInfo(cameraDOPage.getCurrent(), cameraDOPage.getSize(), cameraDOPage.getTotal(), cameraDOPage.getPages()));
    }

    @Override
    public ResponseResult<List<CameraResultVO>> getCameraListByDevice(Integer skylineDeviceId, Integer orgId, Integer cameraPicCount) {
        if (ObjectUtils.isEmpty(skylineDeviceId)) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR);
        }
        List<CameraDO> cameraDOS = cameraMapper.selectList(new LambdaQueryWrapper<CameraDO>()
                .eq(CameraDO::getSkylineDeviceId, skylineDeviceId)
                .eq(CameraDO::getIsDeleted, 0)
                .eq(CameraDO::getOrgId, orgId));

        List<CameraResultVO> resultVOS = new ArrayList<>();
        for (CameraDO cameraDO : cameraDOS) {
            if (cameraDO == null) {
                return ResponseResult.fail(WitmoreErrorCode.CAMERA_NOT_EXIST);
            }
            CameraResultVO build = CameraResultVO.builder()
                    .id(cameraDO.getId())
                    .cameraName(cameraDO.getCameraName())
                    .cameraSn(cameraDO.getCameraSn())
                    .orgId(cameraDO.getOrgId())
                    .type(cameraDO.getType())
                    .modelId(cameraDO.getModelId())
                    .modelName(cameraDO.getModelName())
                    .cameraStatus(cameraDO.getCameraStatus())
                    .build();
            // 查询摄像头图片列表
            Page<CameraPicDO> cameraPicDOPage = cameraPicMapper.selectPage(new Page<>(1, cameraPicCount), new LambdaQueryWrapper<CameraPicDO>()
                    .eq(CameraPicDO::getCameraSn, cameraDO.getCameraSn())
                    .eq(CameraPicDO::getOrgId, cameraDO.getOrgId())
                    .eq(CameraPicDO::getIsDeleted, 0)
                    .orderByDesc(CameraPicDO::getId)
            );
            if (cameraPicDOPage != null && !CollectionUtils.isEmpty(cameraPicDOPage.getRecords())) {
                build.setCameraPicList(cameraPicDOPage.getRecords());
            }
            resultVOS.add(build);
        }

        // 按状态排序 cameraStatus 降序排序
        resultVOS.sort((o1, o2) -> {
            if (o1.getCameraStatus() > o2.getCameraStatus()) {
                return -1;
            } else if (o1.getCameraStatus() < o2.getCameraStatus()) {
                return 1;
            }
            return 0;
        });

        return ResponseResult.success(resultVOS);
    }


    @Override
    public void saveCameraPic(CameraDO cameraDO, String ossUrl, CameraPicSourceTypeEnum sourceTypeEnum) {
        CameraPicDO cameraPicDO = CameraPicDO.builder()
                .cameraSn(cameraDO.getCameraSn())
                .picUrl(ossUrl)
                .skylineCameraId(cameraDO.getId())
                .orgId(cameraDO.getOrgId())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .sourceType(sourceTypeEnum.getCode())
                .isDeleted(0)
                .cameraName(cameraDO.getCameraName())
                .build();
        // 摄像头关联的设备信息
        DeviceDO device = deviceMapper.selectById(cameraDO.getSkylineDeviceId());
        if (device != null) {
            cameraPicDO.setDeviceName(device.getDeviceName());
            cameraPicDO.setDeviceSn(device.getDeviceSn());
        }
        // 摄像头关联的项目信息直接从camera表获取
        if (cameraDO.getProjectId() != null) {
            cameraPicDO.setProjectId(cameraDO.getProjectId());
            ProjectDO projectDO = projectMapper.selectById(cameraDO.getProjectId());
            if (projectDO != null) {
                cameraPicDO.setProjectName(projectDO.getProjectName());
            }
        }
        // 是否启用 AI分析
        OrgDO orgDO = orgMapper.selectById(cameraDO.getOrgId());
        if (orgDO != null && (orgDO.getNeutronEnable() == null || !orgDO.getNeutronEnable())) {
            cameraPicMapper.insert(cameraPicDO);
            return;
        }

        // 执行人体检测和AI分析
        try {
            CameraPicDO analysisResult = pictureAnalysisService.analyzeWithHumanDetection(
                    ossUrl, cameraDO.getCameraSn(), "摄像头抓拍");

            if (analysisResult != null) {
                // 设置分析结果到cameraPicDO
                cameraPicDO.setAnalyzeStatus(analysisResult.getAnalyzeStatus());
                cameraPicDO.setAiMessage(analysisResult.getAiMessage());
                cameraPicDO.setAiLevel(analysisResult.getAiLevel());
                cameraPicDO.setAiLevelType(analysisResult.getAiLevelType());
                cameraPicDO.setAiResult(analysisResult.getAiResult());
                cameraPicMapper.insert(cameraPicDO);

                // 只有在有有效AI分析结果时才发送mqtt消息（即aiLevelType != 0）
                if (analysisResult.getAiLevelType() != null && analysisResult.getAiLevelType() != 0) {
                    messageService.saveMessage(cameraPicDO);
                }
            } else {
                // 分析失败，保存原始记录
                cameraPicMapper.insert(cameraPicDO);
            }
        } catch (Exception e) {
            log.error("图片分析失败，error msg-->{}", e.getMessage());
            // 分析失败时，保存原始记录
            cameraPicMapper.insert(cameraPicDO);
        }

    }


    @Override
    public String convertOssUrl(String fileName, String getUrl) {
        String ossUrl;
        // 调用阿里云服务转存 图片地址
        if (StringUtils.isEmpty(getUrl)) {
            return null;
        }
        log.info("调用阿里云服务转存图片地址 源地：-->{}", getUrl);
        ossUrl = ossClient.uploadFile(fileName, getUrl);
        log.info("调用阿里云服务转存图片地址 目标：-->{}", ossUrl);
        return ossUrl;
    }

    @Override
    public ResponseResult<List<DeviceVideoInfoDTO>> searchVideoYear(List<String> cameraSnList, String year) {
        // 校验参数
        if (CollectionUtils.isEmpty(cameraSnList) || StringUtils.isEmpty(year)) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR);
        }
        // 过滤掉数据库中不存在的摄像头
        List<String> cameraSnListExist = cameraMapper.selectList(new LambdaQueryWrapper<CameraDO>()
                        .in(CameraDO::getCameraSn, cameraSnList)
                        .eq(CameraDO::getIsDeleted, 0)
                        .eq(CameraDO::getCameraStatus, 1)
                        .select(CameraDO::getCameraSn))
                .stream()
                .map(CameraDO::getCameraSn)
                .toList();
        if (CollectionUtils.isEmpty(cameraSnListExist)) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR.getCode(), "摄像头序列号无效或不在线");
        }
        // 调用TPLink接口
        try {
            return ResponseResult.success(ApiVmsStreamClient.getDeviceVideoInfoSearYear(cameraSnListExist, year));
        } catch (Exception e) {
            log.error("搜索存在回放录像的日期失败: {}", e.getMessage());
            return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR);
        }
    }

    @Override
    public ResponseResult<DeviceVideoDayInfo> searchVideoDay(String cameraSn, String searchDay, Integer startIdx, Integer endIdx) {
        // 校验参数
        if (StringUtils.isEmpty(cameraSn) || StringUtils.isEmpty(searchDay) || ObjectUtils.isEmpty(startIdx) || ObjectUtils.isEmpty(endIdx)) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR);
        }
        // 校验日期格式 yyyyMMDD的格式
        LocalDateUtils.validateDate(searchDay, "yyyyMMdd");
        // 校验startIdx不能大于endIdx
        if (startIdx > endIdx) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR.getCode(), "startIdx不能大于endIdx");
        }
        // 校验startIdx和endIdx 差值不能超过100
        if (endIdx - startIdx > 100) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR.getCode(), "startIdx和endIdx差值不能超过100");
        }
        // 摄像头在线状态参数
        this.cameraStatusCheck(cameraSn);
        // 调用TPLink接口
        try {
            return ResponseResult.success(ApiVmsStreamClient.getDeviceVideoInfoSearchDay(cameraSn, searchDay, startIdx, endIdx));
        } catch (Exception e) {
            log.error("搜索当天录像数据失败: 失败原因：{}", e.getMessage());
            return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR);
        }
    }

    @Override
    public ResponseResult<DeviceVideoDayInfo> searchHumanDetectionVideo(String cameraSn, String searchDay) {
        // 校验参数
        if (StringUtils.isEmpty(cameraSn) || StringUtils.isEmpty(searchDay)) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR);
        }
        // 校验日期格式 yyyyMMdd的格式
        LocalDateUtils.validateDate(searchDay, "yyyyMMdd");
        // 摄像头在线状态参数
        this.cameraStatusCheck(cameraSn);
        // 调用TPLink接口
        try {
            return ResponseResult.success(ApiVmsStreamClient.searchHumanDetectionVideo(cameraSn, searchDay));
        } catch (Exception e) {
            log.error("搜索当天所有人形侦测录像数据失败: 失败原因：{}", e.getMessage());
            return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR);
        }
    }

    @Override
    public ResponseResult<List<DeviceSDCardInfo>> getDeviceSDCardInfo(String cameraSn) {
        // 摄像头在线状态参数
        this.cameraStatusCheck(cameraSn);
        // 调用TPLink接口
        try {
            return ResponseResult.success(ApiVmsStreamClient.getDeviceSDCardInfo(cameraSn));
        } catch (Exception e) {
            log.error("获取设备SD卡信息失败: 失败原因：{}", e.getMessage());
            if (e instanceof WitmoreException) {
                return ResponseResult.fail(((WitmoreException) e).getErrorCode());
            }
            return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR);
        }
    }

    /**
     * 比较和记录摄像头状态信息
     *
     * @param cameraSn              摄像头序列号
     * @param cloudMechanicalStatus 云机械状态
     * @param tplinkStatus          TPLink状态
     */
    private void compareAndLogCameraStatus(String cameraSn, Integer cloudMechanicalStatus, Integer tplinkStatus) {
        log.info("摄像头状态对比 - 摄像头SN: {}, 云机械状态: {}, TPLink状态: {}",
                cameraSn, cloudMechanicalStatus, tplinkStatus);

        // 比较云机械状态与TPLink状态
        if (!tplinkStatus.equals(cloudMechanicalStatus)) {
            log.warn("状态不一致[云机械 vs TPLink] - 摄像头SN: {}, 云机械状态: {}, TPLink状态: {}, 采用TPLink状态",
                    cameraSn, cloudMechanicalStatus, tplinkStatus);
        }

        // 记录最终采用的状态
        log.info("摄像头状态确认 - 摄像头SN: {}, 最终采用TPLink状态: {}", cameraSn, tplinkStatus);
    }

    /**
     * 摄像头状态容错机制
     * 调用TPLink接口获取实时状态，与原状态进行比较，以TPLink为准
     *
     * @param cameraSn              摄像头序列号
     * @param cloudMechanicalStatus 云机械原始状态
     * @return 最终状态
     */
    private Integer getCameraStatusWithFailover(String cameraSn, Integer cloudMechanicalStatus) {
        try {
            log.debug("开始获取TPLink实时状态 - 摄像头SN: {}, 云机械状态: {}", cameraSn, cloudMechanicalStatus);

            // 调用TPLink接口获取设备详细信息
            DeviceResultDTO deviceInfo = ApiCaptureUrlClient.getDeviceInfo(cameraSn);

            if (deviceInfo != null && deviceInfo.getDeviceStatus() != null) {
                Integer tplinkRawStatus = deviceInfo.getDeviceStatus();

                // 状态映射：TPLink状态转换为本地状态
                // TPLink: 0-离线, 1-在线, 2-重启中, 3-升级中, 4-配置中, 5-同步中, 6-等待升级
                // 本地: 0-离线, 1-在线
                // 规则: 只有TPLink状态为1时才认为在线，其他状态(0,2,3,4,5,6)均归为离线
                Integer tplinkLocalStatus = (tplinkRawStatus == 1) ? 1 : 0;

                // 详细记录状态映射过程
                String tplinkStatusDesc = this.getTplinkStatusDescription(tplinkRawStatus);
                if (tplinkRawStatus == 1) {
                    log.debug("TPLink状态映射 - 摄像头SN: {}, TPLink原始状态: {} ({}), 映射为本地状态: {} (在线)",
                            cameraSn, tplinkRawStatus, tplinkStatusDesc, tplinkLocalStatus);
                } else {
                    log.info("TPLink状态映射 - 摄像头SN: {}, TPLink原始状态: {} ({}), 映射为本地状态: {} (离线)",
                            cameraSn, tplinkRawStatus, tplinkStatusDesc, tplinkLocalStatus);
                }

                return tplinkLocalStatus;
            } else {
                log.warn("无法获取TPLink设备状态 - 摄像头SN: {}, 返回响应为空或状态字段为空, 使用云机械状态: {}",
                        cameraSn, cloudMechanicalStatus);
                return cloudMechanicalStatus;
            }
        } catch (Exception e) {
            log.error("TPLink状态获取异常 - 摄像头SN: {}, 云机械状态: {}, 异常信息: {}, 使用云机械状态",
                    cameraSn, cloudMechanicalStatus, e.getMessage(), e);
            return cloudMechanicalStatus;
        }
    }

    /**
     * 获取TPLink状态描述
     *
     * @param tplinkStatus TPLink状态码
     * @return 状态描述
     */
    private String getTplinkStatusDescription(Integer tplinkStatus) {
        if (tplinkStatus == null) {
            return "未知状态";
        }

        switch (tplinkStatus) {
            case 0:
                return "离线";
            case 1:
                return "在线";
            case 2:
                return "重启中";
            case 3:
                return "升级中";
            case 4:
                return "配置中";
            case 5:
                return "同步中";
            case 6:
                return "等待升级";
            default:
                return "未知状态[" + tplinkStatus + "]";
        }
    }

    /**
     * 校验摄像头状态
     *
     * @param cameraSn 摄像头序列号
     */
    private void cameraStatusCheck(String cameraSn) {
        if (StringUtils.isEmpty(cameraSn)) {
            throw new WitmoreException(WitmoreErrorCode.PARAM_ERROR);
        }
        CameraDO cameraDO = cameraMapper.selectOne(new LambdaQueryWrapper<CameraDO>()
                .eq(CameraDO::getCameraSn, cameraSn)
                .eq(CameraDO::getIsDeleted, 0));
        if (cameraDO == null) {
            throw new WitmoreException(WitmoreErrorCode.CAMERA_NOT_EXIST);
        }
        // 摄像头离线
        if (cameraDO.getCameraStatus() != 1) {
            throw new WitmoreException(WitmoreErrorCode.CAMERA_OFFLINE);
        }
    }

    @Override
    public ResponseResult<Void> bindCameraToDevice(CameraBindDeviceParamVO paramVO) {
        try {
            // 根据序列号验证设备是否存在
            DeviceDO deviceDO = deviceMapper.selectOne(new LambdaQueryWrapper<DeviceDO>()
                    .eq(DeviceDO::getDeviceSn, paramVO.getDeviceSn())
                    .eq(DeviceDO::getIsDeleted, 0));
            if (deviceDO == null) {
                return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR.getCode(), "设备不存在");
            }
            // 先去TPLink拿摄像头详情
            DeviceResultDTO deviceResultDTO = ApiCaptureUrlClient.getDeviceInfo(paramVO.getCameraSn());
            if (deviceResultDTO == null) {
                return ResponseResult.fail(WitmoreErrorCode.CAMERA_NOT_EXIST);
            }
            // 根据序列号验证摄像头是否存在
            CameraDO cameraDO = cameraMapper.selectOne(new LambdaQueryWrapper<CameraDO>()
                    .eq(CameraDO::getCameraSn, paramVO.getCameraSn())
                    .eq(CameraDO::getIsDeleted, 0));
            if (cameraDO != null) {
                // 摄像头是否已有绑定关系
                if (cameraDO.getSkylineDeviceId() != null) {
                    if (cameraDO.getSkylineDeviceId().equals(deviceDO.getId())) {
                        // 摄像头已绑定，不允许重复绑定
                        return ResponseResult.fail(WitmoreErrorCode.CAMERA_BIND_EXIST);
                    } else {
                        return ResponseResult.fail(WitmoreErrorCode.CAMERA_BIND_EXIST.getCode(), "摄像头已被其他设备绑定，请先解绑");
                    }
                }
                // 摄像头已入库，无绑定关系，直接绑定
                // 获取设备的项目部ID
                Integer deviceProjectId = projectService.getProjectIdByBusinessId(deviceDO.getId(), 1);

                // 构建更新对象
                CameraDO updateCamera = new CameraDO();
                updateCamera.setId(cameraDO.getId());
                updateCamera.setSkylineDeviceId(deviceDO.getId());
                updateCamera.setDeviceSn(deviceDO.getDeviceSn());
                updateCamera.setCameraName(deviceResultDTO.getDeviceName());
                updateCamera.setCameraStatus(deviceResultDTO.getDeviceStatus());
                updateCamera.setModelName(deviceResultDTO.getDeviceModel());
                // 设置摄像头的项目部与设备保持一致
                updateCamera.setProjectId(deviceProjectId != null ? deviceProjectId : 9999);
                int result = cameraMapper.updateById(updateCamera);
                if (result > 0) {
                    return ResponseResult.success();
                } else {
                    return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR.getCode(), "操作失败");
                }
            } else {
                // 新增摄像头并绑定设备
                // 获取设备的项目部ID
                Integer deviceProjectId = projectService.getProjectIdByBusinessId(deviceDO.getId(), 1);

                CameraDO insertCamera = new CameraDO();
                insertCamera.setCameraName(deviceResultDTO.getDeviceName());
                insertCamera.setCameraSn(paramVO.getCameraSn());
                insertCamera.setCameraStatus(deviceResultDTO.getDeviceStatus());
                insertCamera.setOrgId(deviceDO.getOrgId());
                // 设置摄像头的项目部与设备保持一致
                insertCamera.setProjectId(deviceProjectId != null ? deviceProjectId : 9999);
                insertCamera.setSkylineDeviceId(deviceDO.getId());
                insertCamera.setDeviceSn(paramVO.getDeviceSn());
                insertCamera.setType(2);
                insertCamera.setCreateTime(LocalDateTime.now());
                insertCamera.setUpdateTime(LocalDateTime.now());
                insertCamera.setIsDeleted(0);
                insertCamera.setModelName(deviceResultDTO.getDeviceModel());
                int result = cameraMapper.insert(insertCamera);
                if (result > 0) {
                    return ResponseResult.success();
                } else {
                    return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR.getCode(), "操作失败");
                }
            }
        } catch (Exception e) {
            log.error("设备绑定摄像头失败", e);
            return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR.getCode(), "操作失败：" + e.getMessage());
        }
    }

    @Override
    public ResponseResult<Void> updateCameraName(CameraUpdateNameParamVO paramVO) {
        // 设备名称，不能为空，长度限制为 10个中文字符、32个英文字符
        if (StringUtils.isEmpty(paramVO.getCameraName()) || paramVO.getCameraName().length() > 32) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR.getCode(), "设备名称不能为空，长度限制为 10个中文字符、32个英文字符");
        }
        CameraDO cameraDO = cameraMapper.selectOne(new LambdaQueryWrapper<CameraDO>()
                .eq(CameraDO::getCameraSn, paramVO.getCameraSn())
                .eq(CameraDO::getIsDeleted, 0));
        if (cameraDO == null) {
            return ResponseResult.fail(WitmoreErrorCode.CAMERA_NOT_EXIST);
        }
        // 先去TPLink拿摄像头详情
        DeviceResultDTO deviceResultDTO = ApiCaptureUrlClient.getDeviceInfo(paramVO.getCameraSn());
        if (deviceResultDTO == null) {
            return ResponseResult.fail(WitmoreErrorCode.CAMERA_NOT_EXIST);
        }
        if (deviceResultDTO.getOpenStatus() == 0) {
            return ResponseResult.fail(WitmoreErrorCode.CAMERA_OFFLINE.getCode(), "设备处于受限关闭");
        }
        if (deviceResultDTO.getDeviceStatus() != 1) {
            return ResponseResult.fail(WitmoreErrorCode.CAMERA_OFFLINE.getCode(), "设备处于离线状态，无法修改设备名称，请稍后重试");
        }
        TpResultDTO tpResultDTO = ApiCaptureUrlClient.updateDeviceName(paramVO.getCameraSn(), paramVO.getCameraName());
        if (tpResultDTO ==  null || tpResultDTO.getError_code() != 0){
            return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR.getCode(), "操作失败");
        }
        CameraDO updateCamera = new CameraDO();
        updateCamera.setId(cameraDO.getId());
        updateCamera.setCameraName(paramVO.getCameraName());
        updateCamera.setCameraStatus(deviceResultDTO.getDeviceStatus());
        updateCamera.setUpdateTime(LocalDateTime.now());
        int result = cameraMapper.updateById(updateCamera);
        if (result <= 0) {
            return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR.getCode(), "操作失败");
        }
       return ResponseResult.success();
    }

    @Override
    public ResponseResult<Void> updateCameraDeviceSn(CameraUpdateDeviceSnParamVO paramVO) {
        // 根据摄像头序列号查询摄像头信息
        CameraDO cameraDO = cameraMapper.selectById(paramVO.getSkylineCameraId());

        if (cameraDO == null) {
            return ResponseResult.fail(WitmoreErrorCode.PARAM_ERROR.getCode(), "摄像头不存在");
        }

        // 先去TPLink拿摄像头详情
        DeviceResultDTO deviceResultDTO = ApiCaptureUrlClient.getDeviceInfo(paramVO.getCameraSn());
        if (deviceResultDTO == null) {
            return ResponseResult.fail(WitmoreErrorCode.CAMERA_NOT_EXIST);
        }
        if (deviceResultDTO.getOpenStatus() == 0) {
            return ResponseResult.fail(WitmoreErrorCode.CAMERA_OFFLINE.getCode(), "设备处于受限关闭");
        }

        // 更新摄像头的设备序列号
        CameraDO updateCamera = new CameraDO();
        updateCamera.setId(cameraDO.getId());
        updateCamera.setCameraSn(paramVO.getCameraSn());
        updateCamera.setUpdateTime(LocalDateTime.now());

        int result = cameraMapper.updateById(updateCamera);
        if (result <= 0) {
            return ResponseResult.fail(WitmoreErrorCode.SYSTEM_ERROR.getCode(), "更新失败");
        }
        return ResponseResult.success();
    }

}
